package com.nymph.binding;

import com.nymph.mapping.MappedStatement;
import com.nymph.session.SqlSession;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;

/**
 * @Description: This is a sample class.
 * @Author: Simon
 */
public class MapperProxy<T> implements InvocationHandler, Serializable {

    private static final long serialVersionUID = 141342808724869205L;

    private final SqlSession sqlSession;

    private final Class<T> mapperInterface;

    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface)
    {

        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
        try {
            /**
             * 这段代码的意义是对于那些Object类自带的方法，
             * 代理类执行的逻辑与正常没有代理过的类一样
             */
            if (Object.class.equals(method.getDeclaringClass())){
                return method.invoke(this,args);
            }
            return this.execute(method,args);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    //根据SQL指令执行对应操作
    private Object execute(Method method, Object[] args){
        String statementId = this.mapperInterface.getName() + "." + method.getName();
        MappedStatement mappedStatement = this.sqlSession.getConfiguration().getMappedStatement(statementId);

        Object result=null;
        switch (mappedStatement.getSqlCommandType())
        {
            case SELECT:
            {
                Class<?> returnType = method.getReturnType();

                // 如果返回的是list，应该调用查询多个结果的方法，否则只要查单条记录
                if (Collection.class.isAssignableFrom(returnType))
                {
                    //ID为mapper类全名+方法名
                    result = sqlSession.selectList(statementId, args);
                }
                else
                {
                    result = sqlSession.selectOne(statementId, args);
                }
                break;
            }
            case UPDATE:
            {
                sqlSession.update(statementId, args);
                break;
            }
            default:
            {
                //TODO 其他方法待实现
                break;
            }
        }

        return result;
    }
}
